package microcredit.gui.editor.loan;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.Date;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import microcredit.gui.util.FormatUtilities;
import microcredit.gui.util.MDatePicker;
import microcredit.gui.util.NumericTextField;
import microcredit.gui.util.UIUtil;
import microcredit.model.MemberToLoan;
import microcredit.model.bo.BOLoan;
import microcredit.model.domain.LoanStatus;
import microcredit.model.util.ModelUtils;
import net.miginfocom.swing.MigLayout;

public class LoanPanel extends JPanel {
	private JLabel statusLabel;
	private JLabel statusValueLabel;
	private JLabel amountLabel;
	private NumericTextField amountTextField;
	private JLabel interestLabel;
	private NumericTextField interestTextField;
	private JLabel percentLabel;
	private MDatePicker startDateChooser;
	private JLabel startDateLabel;
	private JLabel weeksLabel;
	private JSpinner weeksSpinner;
	private JLabel amountValueLabel;
	private JLabel startDateValueLabel;
	private JLabel interestValueLabel;
	private JLabel weeksValueLabel;
	
	private final LoanGeneralForm form;
	private boolean editable = true;
	private JLabel loanNumberLabel;
	private NumericTextField loanNumberTextField;
	
	public LoanPanel(LoanGeneralForm form) {
		this.form = form;
		
		initialize();
		initListeners();
		
		UIUtil.setMandatoryFields(this, MemberToLoan.LOAN_AMOUNT, MemberToLoan.NUMBER_OF_WEEKS, MemberToLoan.SECURITY1, MemberToLoan.START_DATE);
	}

	private void initListeners(){
		getStartDateChooser().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				form.dataChanged();
			}
		});
		PropertyChangeListener listener = new PropertyChangeListener() {
			public void propertyChange(PropertyChangeEvent e) {
				if ("date".equals(e.getPropertyName())) {
					form.dataChanged();
				}
			}
		};
		 getStartDateChooser().addPropertyChangeListener(listener);
		
		DocumentListener dataChangedDocumentListener = new DocumentListener() {
			@Override
			public void removeUpdate(DocumentEvent e) {
				form.dataChanged();
			}
			@Override
			public void insertUpdate(DocumentEvent e) {
				form.dataChanged();
			}
			@Override
			public void changedUpdate(DocumentEvent e) {
				form.dataChanged();
			}
		};
		
		getAmountTextField().getDocument().addDocumentListener(dataChangedDocumentListener);
		getInterestTextField().getDocument().addDocumentListener(dataChangedDocumentListener);
		
		getWeeksSpinner().addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				form.dataChanged();
			}
		});
	}
	
	public void apply(MemberToLoan loan) {
		updateData(loan);
		updateStatus(loan);
		updateState(loan);
		
		revalidate();
		repaint();
	}
	
	private void updateData(MemberToLoan loan) {
		int weeks = loan.getNumberOfWeeks();
		BigDecimal loanAmount = loan.getLoanAmount();
		BigDecimal interest = loan.getInterestPercentage();
		Date startDate = loan.getStartDate();
		Long loanNumber = loan.getSequenceID();
		
		if (loanNumber == null) {
			loanNumber = BOLoan.create().generateSequenceID(loan.getMember());
		}
		if (loanNumber != null) {
			loanNumber = loanNumber+1;
		}
		
		
		getStartDateChooser().setDate(startDate);
		getWeeksSpinner().setValue(weeks);
		if (interest == null)  {
			getInterestTextField().setValue(new BigDecimal(0));
		} else {
			getInterestTextField().setValue(interest);
		}
		
		Number numberValue = null;
		try {
			numberValue = getAmountTextField().getNumberValue();
		} catch (ParseException e) {
		}
		if (!ModelUtils.equals(numberValue, loanAmount)) {
			getAmountTextField().setText(FormatUtilities.formatMoney(loan.getLoanAmount()));
		}
		
		getStartDateValueLabel().setText(FormatUtilities.formatDate(startDate));
		getAmountValueLabel().setText(FormatUtilities.formatMoney(loanAmount));
		getInterestValueLabel().setText(FormatUtilities.formatMoney(interest)+" %");
		getWeeksValueLabel().setText(weeks+"");
		
		if (loanNumber != null) {
			getLoanNumberTextField().setValue(loanNumber);
		}
	}
	
	
	public MemberToLoan receive(MemberToLoan loan) {
		if (isEditable()) {
			Integer weeks = (Integer)getWeeksSpinner().getValue();
			BigDecimal loanAmount = null;
			try {
				loanAmount = (BigDecimal)getAmountTextField().getNumberValue();
			} catch (ParseException e) {
			}
			BigDecimal interest = null;
			try {
				interest = (BigDecimal)getInterestTextField().getNumberValue();
			} catch (ParseException e) {
			}
			Date startDate = getStartDateChooser().getDate();
			if (weeks != null) {
				loan.setNumberOfWeeks(weeks);
				if (loan.getLastHistory() != null) {
					loan.getLastHistory().setNewNumberOfWeeks(weeks);
				}
			}
			loan.setLoanAmount(loanAmount);
			loan.setInterestPercentage(interest);
			loan.setStartDate(startDate);
			
			try {
				Number n = getLoanNumberTextField().getNumberValue();
				if (n != null) {
					long longValue = n.longValue();
					longValue--;
					loan.setCustomSequenceID(longValue);
				}
			} catch (ParseException e) {
			}
		}
		return loan;
	}
	
	private void updateState(MemberToLoan loan) {
		boolean extension = loan.hasExtension();
		boolean entryFinalized = loan.isEntryFinalized();
		
		setEditable(!entryFinalized && !extension);
		
		getLoanNumberTextField().setEditable(loan.isNew());
		getLoanNumberTextField().setEnabled(loan.isNew());
	}
	
	private void updateStatus(MemberToLoan loan) {
		LoanStatus status = loan.getLoanStatus();
		getStatusValueLabel().setText(loan.createStatusString());
		if (status != null) {
			switch (status) {
			case A :
				getStatusValueLabel().setForeground(Color.BLUE);
				break;
			case F :
				getStatusValueLabel().setForeground(Color.decode("#166d18"));
				break;
			case N :
				getStatusValueLabel().setForeground(Color.RED);
				break;
			case R :
				getStatusValueLabel().setForeground(Color.decode("#8e8a23"));
				break;
			case K :
				getStatusValueLabel().setForeground(Color.decode("#166d18"));
				break;
			}
		}
	}

	
	public void setEditable(boolean editable) {
		getAmountValueLabel().setVisible(!editable);
		getInterestValueLabel().setVisible(!editable);
		getStartDateValueLabel().setVisible(!editable);
		getWeeksValueLabel().setVisible(!editable);
		
		getAmountTextField().setVisible(editable);
		getInterestTextField().setVisible(editable);
		getPercentLabel().setVisible(editable);
		getStartDateChooser().setVisible(editable);
		getWeeksSpinner().setVisible(editable);
	}
	
	
	public boolean isEditable() {
		return editable;
	}
	
	private void initialize() {
		setLayout(new MigLayout("insets 0, hidemode 3", "[][right][grow][right][grow][][grow]", "[][][][][]"));
		add(getStatusLabel(), "cell 1 1");
		add(getStatusValueLabel(), "cell 2 1");
		add(getLoanNumberLabel(), "cell 3 1,alignx trailing");
		add(getLoanNumberTextField(), "cell 4 1");
		add(getAmountLabel(), "cell 1 2");
		add(getAmountTextField(), "flowx,cell 2 2");
		add(getInterestLabel(), "cell 3 2");
		add(getInterestTextField(), "flowx,cell 4 2");
		add(getStartDateLabel(), "cell 1 3");
		add(getStartDateChooser(), "flowx,cell 2 3");
		add(getWeeksLabel(), "cell 3 3");
		add(getWeeksSpinner(), "flowx,cell 4 3");
		add(getAmountValueLabel(), "cell 2 2");
		add(getPercentLabel(), "cell 4 2");
		add(getInterestValueLabel(), "cell 4 2");
		add(getStartDateValueLabel(), "cell 2 3");
		add(getWeeksValueLabel(), "cell 4 3");
	}
	
	private JLabel getStatusLabel() {
		if (statusLabel == null) {
			statusLabel = new JLabel("Status:");
		}
		return statusLabel;
	}
	
	private JLabel getStatusValueLabel() {
		if (statusValueLabel == null) {
			statusValueLabel = new JLabel("Pending");
			statusValueLabel.setFont(statusValueLabel.getFont().deriveFont(statusValueLabel.getFont().getStyle() | Font.BOLD, statusValueLabel.getFont().getSize() + 3f));
		}
		return statusValueLabel;
	}
	private JLabel getAmountLabel() {
		if (amountLabel == null) {
			amountLabel = new JLabel("Loan:");
		}
		return amountLabel;
	}
	
	private NumericTextField getAmountTextField() {
		if (amountTextField == null) {
			amountTextField = new NumericTextField();
			amountTextField.setColumns(10);
			amountTextField.setName(MemberToLoan.LOAN_AMOUNT);
		}
		return amountTextField;
	}
	
	private JLabel getInterestLabel() {
		if (interestLabel == null) {
			interestLabel = new JLabel("Interest:");
		}
		return interestLabel;
	}
	
	private NumericTextField getInterestTextField() {
		if (interestTextField == null) {
			interestTextField = new NumericTextField();
			interestTextField.setColumns(3);
			interestTextField.setName(MemberToLoan.INTEREST_PERCENTAGE);
		}
		return interestTextField;
	}
	
	private JLabel getPercentLabel() {
		if (percentLabel == null) {
			percentLabel = new JLabel("%");
		}
		return percentLabel;
	}
	
	private MDatePicker getStartDateChooser() {
		if (startDateChooser == null) {
			startDateChooser = new MDatePicker();
			startDateChooser.setName(MemberToLoan.START_DATE);
		}
		return startDateChooser;
	}
	
	private JLabel getStartDateLabel() {
		if (startDateLabel == null) {
			startDateLabel = new JLabel("Start date:");
		}
		return startDateLabel;
	}
	
	private JLabel getWeeksLabel() {
		if (weeksLabel == null) {
			weeksLabel = new JLabel("No of weeks:");
		}
		return weeksLabel;
	}
	
	private JSpinner getWeeksSpinner() {
		if (weeksSpinner == null) {
			weeksSpinner = new JSpinner();
			weeksSpinner.setModel(new SpinnerNumberModel(0, 0, 200, 1));
			weeksSpinner.setName(MemberToLoan.NUMBER_OF_WEEKS);
		}
		return weeksSpinner;
	}
	private JLabel getAmountValueLabel() {
		if (amountValueLabel == null) {
			amountValueLabel = new JLabel("100");
		}
		return amountValueLabel;
	}
	private JLabel getStartDateValueLabel() {
		if (startDateValueLabel == null) {
			startDateValueLabel = new JLabel("25 December 2010");
		}
		return startDateValueLabel;
	}
	private JLabel getInterestValueLabel() {
		if (interestValueLabel == null) {
			interestValueLabel = new JLabel("5%");
		}
		return interestValueLabel;
	}
	private JLabel getWeeksValueLabel() {
		if (weeksValueLabel == null) {
			weeksValueLabel = new JLabel("3");
		}
		return weeksValueLabel;
	}

	public void focusDefault() {
		getAmountTextField().requestFocus();
		getAmountTextField().selectAll();
	}
	private JLabel getLoanNumberLabel() {
		if (loanNumberLabel == null) {
			loanNumberLabel = new JLabel("Loan No:");
		}
		return loanNumberLabel;
	}
	private NumericTextField getLoanNumberTextField() {
		if (loanNumberTextField == null) {
			loanNumberTextField = new NumericTextField();
			loanNumberTextField.setColumns(3);
			loanNumberTextField.setName(MemberToLoan.SEQUENCE_ID);
		}
		return loanNumberTextField;
	}
}
